gusucode.com > VC++ EMF图片浏览器(可读emf、wmf、emz、wmz、png……等)-源码程序 > VC++ EMF图片浏览器(可读emf、wmf、emz、wmz、png……等)-源码程序/code/Src/Client/scemflib/SCDCRendRgns_i.cpp
//Download by http://www.NewXing.com /* * This file is part of the EMFexplorer projet. * Copyright (C) 2004 Smith Charles. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * * Extension: for commercial use, apply the Equity Public License, which * adds to the normal terms of the GLPL a condition of donation to the author. * If you are interested in support for this source code, * contact Smith Charles <smith.charles@free.fr> for more information. */ #include "stdafx.h" #include "SCEMFdcRenderer.h" using namespace Gdiplus; // Debug stuff #ifdef _DEBUG void SCMarkBox(GDPGraphics* pGraphics, RECT rcBox, COLORREF crColor, int iDltx=0, int iDlty=0, int iDltR=0, int iDltB=0); #define SCSHOW_REDLIMIT() \ { \ RECT box;\ ::CopyRect(&box, &m_RcClipBox);\ ::InflateRect(&box, -1, -1);\ SCDPtoLP((Point*)&box, 2);\ SCMarkBox(m_pGraphics, box, RGB(255, 0, 0));\ } #define SCSHOW_BLUELIMIT() \ { \ RECT box;\ ::CopyRect(&box, &m_RcClipBox);\ ::InflateRect(&box, -2, -2);\ SCDPtoLP((Point*)&box, 2);\ SCMarkBox(m_pGraphics, box, RGB(0, 0, 255));\ } #define SCSHOW_DPRCLIMIT(rbox, rcolor) \ { \ RECT box;\ ::CopyRect(&box, &rbox);\ ::InflateRect(&box, -2, -2);\ SCDPtoLP((Point*)&box, 2);\ SCMarkBox(m_pGraphics, box, rcolor);\ } #define SCSHOW_LPRCLIMIT(rbox, rcolor) \ { \ RECT box;\ ::CopyRect(&box, &rbox);\ ::InflateRect(&box, -4, -4);\ SCMarkBox(m_pGraphics, box, rcolor);\ } #else #define SCSHOW_REDLIMIT() #define SCSHOW_BLUELIMIT() #endif /////////////////////////////////////////////////////////////////////////////////////// // Regions/Clipping rects management // void CSCEMFdcRenderer::SCIntersectClipRect(RECTL& rRect) { ASSERT(m_pGraphics); Rect R(rRect.left, rRect.top, RECT_WIDTH(rRect), RECT_HEIGHT(rRect)); m_pGraphics->SetClip(R, CombineModeIntersect); } void CSCEMFdcRenderer::SCExcludeClipRect(RECTL& rRect) { ASSERT(m_pGraphics); Rect R(rRect.left, rRect.top, RECT_WIDTH(rRect), RECT_HEIGHT(rRect)); m_pGraphics->SetClip(R, CombineModeExclude); } void CSCEMFdcRenderer::SCOffsetClipRect(POINTL& rPtOffset) { ASSERT(m_pGraphics); m_pGraphics->TranslateClip(rPtOffset.x, rPtOffset.y); #pragma message( __FILE__ "(90): TODO: Consider cropping ") //if (would overflow) //SCCropToPlayBox(CombineModeIntersect); } /// /// Use REGIONDATA pointed to by pData to select a new GDI+ region. /// void CSCEMFdcRenderer::SCSelectClipRgn(LPCBYTE pData, DWORD dwSize, DWORD dwMode) { ASSERT(m_pGraphics); if (!dwSize || !pData) { // This would allow writing outside the original playing rectangle: // m_pGraphics->ResetClip(); SCCropToPlayBox(); } else { // This generates jagged regions, as we don't have a region smoothing function HRGN hRgn = SCGetHRGNFromREGIONDATA(pData, dwSize); ASSERT(hRgn); #if 0 // won't work (maybe this SetClip expects device coordinates in hRgn) m_pGraphics->SetClip(hRgn, SCClipModeFormRGNMode(dwMode)); #else // hRgn contains world coordinates Region region(hRgn); ASSERT(Ok==region.GetLastStatus()); m_pGraphics->SetClip(®ion, SCClipModeFormRGNMode(dwMode)); #endif DeleteObject(hRgn); // assume the GDI+ object doesn't need it anymore Status iRes = m_pGraphics->GetLastStatus(); ASSERT(Ok==iRes); // Can't explain an iRes==OutOfMemory for a region containing 1 rect of (790x600) // while the scale transform is m11=m22=0.066724 } } /// /// Create a GDI region from REGIONDATA. /// "The ExtSelectClipRgn function assumes that the coordinates /// for the specified region are specified in device units". So we assume that the region /// data is in device coordinates. /// /// "A GDI+ region is stored in world coordinates whereas a GDI region is stored in device coordinates." /// We prepare the region in world coordinates (ready for a GDI+ region constructor). /// HRGN CSCEMFdcRenderer::SCGetHRGNFromREGIONDATA(LPCBYTE pData, DWORD dwSize) { ASSERT(pData && dwSize); LPBYTE pBytes = new BYTE[dwSize]; ASSERT(pBytes); if (!pBytes) return NULL; memmove(pBytes, pData, dwSize); RGNDATA* pRgnData = (RGNDATA *)pBytes; ASSERT(pRgnData->rdh.iType == RDH_RECTANGLES); Matrix matrix; m_pGraphics->GetTransform(&matrix); matrix.Invert(); RECT* pRect = (RECT*)pRgnData->Buffer; matrix.TransformPoints((Point*)pRgnData->Buffer, pRgnData->rdh.nCount*2); // DP to LP HRGN hRgn = ::ExtCreateRegion(NULL, dwSize, pRgnData); ASSERT(hRgn); // Meta region simulation CRect rcMeta(m_RcClipBox.left, m_RcClipBox.top, m_RcClipBox.right, m_RcClipBox.bottom); matrix.TransformPoints((Point*)&rcMeta, 2); // DP to LP HRGN hRgnMeta = ::CreateRectRgn(rcMeta.left, rcMeta.top, rcMeta.right, rcMeta.bottom); ASSERT(hRgnMeta); int iRes = CombineRgn(hRgn, hRgn, hRgnMeta, RGN_AND); ASSERT(iRes!=ERROR); DeleteObject(hRgnMeta); delete [] pBytes; return hRgn; } /// /// Fill a region by using the specified brush. /// void CSCEMFdcRenderer::SCFillRgn(HBRUSH hBrush, LPCBYTE pData, DWORD dwSize) { ASSERT(m_pGraphics); ASSERT(pData && dwSize); ASSERT(hBrush); HRGN hRgn = SCGetHRGNFromREGIONDATA(pData, dwSize); ASSERT(hRgn); Region region(hRgn); DeleteObject(hRgn); // assume the GDI+ object doesn't need it anymore LOGBRUSH LogBrush; ::GetObject(hBrush, sizeof(LOGBRUSH), &LogBrush); SCShortDCState TmpDCState(m_bMonochrome, m_dwROP2, m_TextColor, m_BkColor, m_dwBkMode); Brush* pBrush = SCBrushFromLogBrush(LogBrush, TmpDCState); m_pGraphics->FillRegion(pBrush, ®ion); delete pBrush; } /// /// Draw a border around the specified region by using the specified brush. /// void CSCEMFdcRenderer::SCFrameRgn(HBRUSH hBrush, SIZEL szlStroke, LPCBYTE pData, DWORD dwSize) { ASSERT(m_pGraphics); ASSERT(pData && dwSize); ASSERT(hBrush); HRGN hRgn = SCGetHRGNFromREGIONDATA(pData, dwSize); ASSERT(hRgn); Region region(hRgn); DeleteObject(hRgn); // assume the GDI+ object doesn't need it anymore LOGBRUSH LogBrush; ::GetObject(hBrush, sizeof(LOGBRUSH), &LogBrush); SCShortDCState TmpDCState(m_bMonochrome, m_dwROP2, m_TextColor, m_BkColor, m_dwBkMode); Brush* pBrush = SCBrushFromLogBrush(LogBrush, TmpDCState); Rect Bounds; region.GetBounds(&Bounds, m_pGraphics); Rect rect = Bounds; // vertical bands rect.X -= szlStroke.cx; // account for V stroke width rect.Width = szlStroke.cx; m_pGraphics->FillRectangle(pBrush, rect); rect.X += Bounds.Width + szlStroke.cx; m_pGraphics->FillRectangle(pBrush, rect); // horizontal bands rect.X = Bounds.X - szlStroke.cx; // account for V stroke width rect.Y = Bounds.Y - szlStroke.cy; // account for H stroke width rect.Height = szlStroke.cy; rect.Width = Bounds.Width + 2*szlStroke.cx; m_pGraphics->FillRectangle(pBrush, rect); rect.Y += Bounds.Height + szlStroke.cy; m_pGraphics->FillRectangle(pBrush, rect); delete pBrush; } /// /// Invert the colors in the specified region. /// void CSCEMFdcRenderer::SCInvertRgn(LPCBYTE pData, DWORD dwSize) { ASSERT(m_pGraphics); ASSERT(pData && dwSize); HRGN hRgn = SCGetHRGNFromREGIONDATA(pData, dwSize); ASSERT(hRgn); Region region(hRgn); DeleteObject(hRgn); // assume the GDI+ object doesn't need it anymore Region SvdClipRgn; m_pGraphics->GetClip(&SvdClipRgn); m_pGraphics->SetClip(®ion, CombineModeIntersect); Rect Bounds; region.GetBounds(&Bounds, m_pGraphics); RECT rcRgnBox; rcRgnBox.left = Bounds.X; rcRgnBox.top = Bounds.Y; rcRgnBox.right = rcRgnBox.left + Bounds.Width; rcRgnBox.bottom = rcRgnBox.top + Bounds.Height; SCPatBlt(&rcRgnBox, DSTINVERT, NULL); m_pGraphics->SetClip(&SvdClipRgn); } /// /// Paint the specified region by using the current brush /// void CSCEMFdcRenderer::SCPaintRgn(LPCBYTE pData, DWORD dwSize) { ASSERT(m_pGraphics); ASSERT(pData && dwSize); ASSERT(m_pBrush); HRGN hRgn = SCGetHRGNFromREGIONDATA(pData, dwSize); ASSERT(hRgn); Region region(hRgn); DeleteObject(hRgn); // assume the GDI+ object doesn't need it anymore Region SvdClipRgn; m_pGraphics->GetClip(&SvdClipRgn); m_pGraphics->SetClip(®ion, CombineModeIntersect); Rect Bounds; region.GetBounds(&Bounds, m_pGraphics); RECT rcRgnBox; rcRgnBox.left = Bounds.X; rcRgnBox.top = Bounds.Y; rcRgnBox.right = rcRgnBox.left + Bounds.Width; rcRgnBox.bottom = rcRgnBox.top + Bounds.Height; SCPatBlt(&rcRgnBox, PATPAINT, NULL); m_pGraphics->SetClip(&SvdClipRgn); } /// /// Reset the clipping region after meta region has changed. /// /// The current clipping region of a device context is defined by the intersection /// of its clipping region and its metaregion. /// void CSCEMFdcRenderer::SCOnSetMetaRgn() { // After SetMetaRgn, "the clipping region is reset to a null region". // So we do a reset. #ifdef _DEBUG {// check that there is no clipping region HRGN hRgn = ::CreateRectRgn(0, 0, 0, 0); ASSERT(hRgn); if (hRgn) { ASSERT(0==::GetClipRgn(m_hDC, hRgn)); } } #endif // In case of problem, activate and call SCOnChangeClipping() instead of this SCCropToPlayBox(); } /// /// Ensure no writing occurs outside the original playing rectangle /// void CSCEMFdcRenderer::SCCropToPlayBox(CombineMode nCropMode/*=CombineModeReplace*/) { // Meta region simulation CRect rcMeta(m_RcClipBox.left, m_RcClipBox.top, m_RcClipBox.right, m_RcClipBox.bottom); SCDPtoLP((Point*)&rcMeta, 2); Rect rectClip(rcMeta.left, rcMeta.top, RECT_WIDTH(rcMeta), RECT_HEIGHT(rcMeta)); m_pGraphics->SetClip(rectClip, nCropMode); } #if 0 // Code to activate in case of problems with metaregion /// /// Convert the current clipping region in m_hDC to its corresponding GDI+ region. /// void CSCEMFdcRenderer::SCOnChangeClipping() { HRGN hRgn = ::CreateRectRgn(0, 0, 0, 0); ASSERT(hRgn); if (hRgn) { switch (::GetClipRgn(m_hDC, hRgn)) { case 1: m_pGraphics->SetClip(hRgn); break; case 0: SCCropToPlayBox(); break; default: ASSERT(0); } ::DeleteObject(hRgn); } } #endif /////////////////////////////////////////////////////////////////////////////////////// // Debug helpers // #ifdef _DEBUG void SCMarkBox(GDPGraphics* pGraphics, RECT rcBox, COLORREF crColor, int iDltx/*=0*/, int iDlty/*=0*/, int iDltR/*=0*/, int iDltB/*=0*/) { Color PenColor; PenColor.SetFromCOLORREF(crColor); Pen pen(PenColor, 1.0); Rect rect(rcBox.left + iDltx, rcBox.top + iDlty, RECT_WIDTH(rcBox) - (iDltx + iDltR), RECT_HEIGHT(rcBox) - (iDlty + iDltB)); pGraphics->DrawRectangle(&pen, rect); } #endif